package com.henme.crm.util.shiro;

import com.henme.crm.dao.admin.AuthorityMapper;
import com.henme.crm.dao.admin.UserMapper;
import com.henme.crm.entity.admin.Authority;
import com.henme.crm.entity.admin.Role;
import com.henme.crm.entity.admin.User;
import com.henme.crm.service.admin.AuthorityService;
import com.henme.crm.service.admin.RoleService;
import com.henme.crm.service.admin.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;



public class ShiroDbRealm extends AuthorizingRealm {
	
	@Autowired
	private UserService userService;

    @Autowired
    private AuthorityService authorityService;

    @Autowired
    private RoleService roleService;

	/**
	 * 认证回调函数, 登录时调用.
	 */
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		User user = userService.queryUniqueByUsername(token.getUsername());
        checkUser(user) ;
		if (user != null) {
			return new SimpleAuthenticationInfo(new ShiroUser(user.getUsername(), user.getUsername()), user.getPassword(),
					getName());
		} else {
			return null;
		}
	}

    private void checkUser(User user) {
        if (null == user) {
            throw new UnknownAccountException("No account found for user [" + user.getUsername() + "]");
        }

        if (!user.isAccountNonLocked()) {
            throw new LockedAccountException("Account found for user [" + user.getUsername() + "] is locked");
        }
    }

    /**
	 * 授权查询回调函数, private void checkUser(User ) {
    }进行鉴权但缓存中无用户的授权信息时调用.
	 */
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		ShiroUser shiroUser = (ShiroUser) principals.fromRealm(getName()).iterator().next();
        String userName= shiroUser.getLoginName().trim();
        //如果是admin的用户登录就具有所有权限
        if("admin".equals(userName)){
            List<Role> listRole=roleService.getRoleList();
            Set<String> setRole=new HashSet<String>();
            for(Role r:listRole){
                setRole.add(r.getName());
            }
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(setRole);
            List<Authority> list=authorityService.getAllAuthorityList();
            Set<String> set=new HashSet<String>();
            for(Authority a:list){
               set.add(a.getPermission())  ;
            }
            info.setStringPermissions(set);
            return info;
        }
		User user = userService.queryUniqueByUsername(userName);
		if (user != null) {
			//SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			Set<String> roleNames = new HashSet<String>();		
			Set<String> permissions = new HashSet<String>();
		  	for(Role r:user.getRoles()){
		  			roleNames.add(r.getName());
	    		 for(Authority a:r.getAuthorities()){
	    			 permissions.add(a.getPermission());
	    		 }
	    	}
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
			info.setStringPermissions(permissions);
			return info;
		} else {
			return null;
		}
	}

	/**
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}



	/**
	 * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.
	 */
	public static class ShiroUser implements Serializable {

		private static final long serialVersionUID = -1748602382963711884L;
		private String loginName;
		private String name;

		public ShiroUser(String loginName, String name) {
			this.loginName = loginName;
			this.name = name;
		}

		public String getLoginName() {
			return loginName;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return loginName;
		}

		public String getName() {
			return name;
		}
	}
}
